package sharedjplaylist.client.top;

import java.util.ArrayList;

import sharedjplaylist.client.BaseComposite;
import sharedjplaylist.client.playlist.CreatePlaylist;
import sharedjplaylist.client.service.PlaylistService;
import sharedjplaylist.client.service.PlaylistServiceAsync;
import sharedjplaylist.client.utils.Encrypter;
import sharedjplaylist.shared.model.Playlist;
import sharedjplaylist.shared.model.Tunelist;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.Hidden;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.TreeItem;
import com.google.gwt.user.client.ui.Widget;

public class PlaylistBrowse extends BaseComposite{

    private static PlaylistBrowseUiBinder uiBinder = GWT.create(PlaylistBrowseUiBinder.class);

    static String ANY = "any";

    protected PlaylistServiceAsync playlistService = GWT.create(PlaylistService.class);

    ArrayList<Playlist> rootPlaylistList;

    ArrayList<String> dateList;

    ArrayList<String> eventnameList;

    ArrayList<String> djnameList;

    interface PlaylistBrowseUiBinder extends UiBinder<Widget, PlaylistBrowse>{
    }

    @UiField
    ListBox dateListBox;

    @UiField
    ListBox eventnameListBox;

    @UiField
    ListBox djnameListBox;

    @UiField
    Button resetButton;

    @UiField
    Tree playlistTree;

    @UiField
    Label noneLabel;

    @UiField
    HTMLPanel playlistPanel;

    @UiField
    Label djnameLabel;

    @UiField
    Label eventnameLabel;

    @UiField
    Label genreLabel;

    @UiField
    Label dateLabel;

    @UiField
    TextBox linkTextBox;

    @UiField
    Label commentLabel;

    @UiField
    Hidden keyHidden;

    @UiField
    Hidden passwordHidden;

    @UiField
    FlexTable playlistFlexTable;

    @UiField
    TextBox passwordTextBox;

    @UiField
    Button editButton;

    @UiField
    Button deleteButton;

    public PlaylistBrowse(){
        initWidget(uiBinder.createAndBindUi(this));
        getPlaylistList();
    }

    public PlaylistBrowse(String token){
        initWidget(uiBinder.createAndBindUi(this));
        String hiddenvalue = "Playlist(" + token + ")";
        getPlaylistList(hiddenvalue);
    }

    private void getPlaylistList(final String hiddenvalue){
        playlistService.getPlaylistList(new AsyncCallback<ArrayList<Playlist>>(){

            public void onSuccess(ArrayList<Playlist> result){
                rootPlaylistList = result;
                setListBox();
                setButton();
                setTree(rootPlaylistList);
                setPlaylistFlexTable(hiddenvalue);
            }

            public void onFailure(Throwable caught){
                clearInfoMessage();
                setErrorMessage("Playlistの取得に失敗しました。");
            }
        });

    }

    private void getPlaylistList(){
        playlistService.getPlaylistList(new AsyncCallback<ArrayList<Playlist>>(){

            public void onSuccess(ArrayList<Playlist> result){
                rootPlaylistList = result;
                setListBox();
                setButton();
                setTree(rootPlaylistList);
            }

            public void onFailure(Throwable caught){
                clearInfoMessage();
                setErrorMessage("Playlistの取得に失敗しました。");
            }
        });
    }

    protected void setButton(){
        resetButton.addClickHandler(new ClickHandler(){

            public void onClick(ClickEvent event){
                clearListBox();
            }
        });

        editButton.addClickHandler(new ClickHandler(){

            public void onClick(ClickEvent event){
                if(checkPassword()){
                    setEdit();
                }
            }
        });

        deleteButton.addClickHandler(new ClickHandler(){

            public void onClick(ClickEvent event){
                if(checkPassword()){
                    setDelete();
                }
            }
        });
    }

    protected boolean checkPassword(){
        String passwordHash = Encrypter.getHash(passwordTextBox.getText(), Encrypter.ALG_SHA256);
        if(passwordHidden.getValue().equals(passwordHash)){
            clearInfoMessage();
            clearErrorMessage();
            return true;
        }else{
            clearInfoMessage();
            setErrorMessage("パスワードが間違っています。");
            return false;
        }
    }

    protected void clearListBox(){
        dateListBox.setSelectedIndex(0);
        eventnameListBox.setSelectedIndex(0);
        djnameListBox.setSelectedIndex(0);
        changeTree();
    }

    protected void setTree(ArrayList<Playlist> playlistList){

        if(playlistList.size() < 1){
            playlistTree.setVisible(false);
            noneLabel.setVisible(true);
            return;
        }else{
            playlistTree.setVisible(true);
            noneLabel.setVisible(false);
        }

        playlistTree.clear();
        setArrayList(playlistList);

        for(String date:dateList){
            playlistTree.addItem(new TreeItem(date));
        }

        for(int i = 0;i < playlistTree.getItemCount();i++){
            TreeItem currentTree = playlistTree.getItem(i);
            ArrayList<Playlist> currentPlaylist = getPlaylistDate(currentTree.getText(), playlistList);

            setArrayList(currentPlaylist);

            for(String eventname:eventnameList){
                currentTree.addItem(new TreeItem(eventname));
            }

            for(int j = 0;j < currentTree.getChildCount();j++){
                TreeItem currentTreeItem = currentTree.getChild(j);
                currentPlaylist = getPlaylistDateEventName(currentTree.getText(), currentTreeItem.getText(), playlistList);

                setArrayList(currentPlaylist);

                for(String djname:djnameList){
                    TreeItem djnameTreeItem = new TreeItem(djname);
                    for(Playlist playlist:currentPlaylist){
                        if(playlist.getDJName().equals(djname)){
                            djnameTreeItem.setTitle(playlist.getKey().toString());
                        }
                    }
                    setTreeItem(djnameTreeItem);
                    currentTreeItem.addItem(djnameTreeItem);
                }
            }
        }
    }

    private void setTreeItem(final TreeItem djnameTreeItem){
        playlistTree.addSelectionHandler(new SelectionHandler<TreeItem>(){

            public void onSelection(SelectionEvent<TreeItem> event){
                if(djnameTreeItem == event.getSelectedItem()){
                    setPlaylistFlexTable(djnameTreeItem.getTitle());
                }
            }
        });
    }

    protected void setPlaylistFlexTable(String title){
        Playlist currentPlaylist = null;

        for(Playlist playlist:rootPlaylistList){
            if(playlist.getKey().toString().equals(title)){
                currentPlaylist = playlist;
                break;
            }
        }

        if(currentPlaylist != null){
            eventnameLabel.setText(currentPlaylist.getEventName());
            djnameLabel.setText(currentPlaylist.getDJName());
            genreLabel.setText(currentPlaylist.getGenre());
            dateLabel.setText(currentPlaylist.getDatetime());
            commentLabel.setText(currentPlaylist.getComment());
            keyHidden.setValue(currentPlaylist.getKey().toString());
            passwordHidden.setValue(currentPlaylist.getPassword());

            linkTextBox.setText("http://" + Window.Location.getHost() + Window.Location.getPath() + "#" + currentPlaylist.getKey().getId());
            setTunelist(currentPlaylist.getTunelist());
            playlistPanel.setVisible(true);
        }
    }


    private void setTunelist(ArrayList<Tunelist> tunelistList){
        playlistFlexTable.removeAllRows();
        int row = 0;

        playlistFlexTable.setText(row, 1, "Title/Artist");
        playlistFlexTable.setText(row, 2, "Comment");

        row++;

        for(Tunelist tunelist:tunelistList){
            playlistFlexTable.setText(row, 0, String.valueOf(row));
            playlistFlexTable.setText(row, 1, tunelist.getTune_artist());
            playlistFlexTable.setText(row, 2, tunelist.getComment());
            row++;
        }
    }

    private ArrayList<Playlist> getPlaylistDateEventNameDJName(String date, String eventname, String djname){
        ArrayList<Playlist> currentPlaylist = new ArrayList<Playlist>();

        for(Playlist playlist:rootPlaylistList){
            boolean containFlag = true;

            if(!date.equals(ANY)){
                if(!date.equals(playlist.getDatetime().substring(0, 7))){
                    containFlag = false;
                }
            }

            if(!eventname.equals(ANY)){
                if(!eventname.equals(playlist.getEventName())){
                    containFlag = false;
                }
            }

            if(!djname.equals(ANY)){
                if(!djname.equals(playlist.getDJName())){
                    containFlag = false;
                }
            }

            if(containFlag){
                currentPlaylist.add(playlist);
            }

        }


        return currentPlaylist;
    }

    private ArrayList<Playlist> getPlaylistDateEventName(String date, String eventname, ArrayList<Playlist> playlistList){
        ArrayList<Playlist> currentPlaylist = new ArrayList<Playlist>();

        for(Playlist playlist:playlistList){
            if(playlist.getDatetime().contains(date) && playlist.getEventName().contains(eventname)){
                currentPlaylist.add(playlist);
            }
        }

        return currentPlaylist;
    }

    private ArrayList<Playlist> getPlaylistDate(String date, ArrayList<Playlist> playlistList){
        ArrayList<Playlist> currentPlaylist = new ArrayList<Playlist>();

        for(Playlist playlist:playlistList){
            if(playlist.getDatetime().contains(date)){
                currentPlaylist.add(playlist);
            }
        }

        return currentPlaylist;
    }

    protected void setListBox(){
        getListBox();
        setListBoxHandler();
    }

    private void setListBoxHandler(){
        dateListBox.addChangeHandler(new ChangeHandler(){

            public void onChange(ChangeEvent event){
                changeTree();
            }
        });

        eventnameListBox.addChangeHandler(new ChangeHandler(){

            public void onChange(ChangeEvent event){
                changeTree();
            }
        });

        djnameListBox.addChangeHandler(new ChangeHandler(){

            public void onChange(ChangeEvent event){
                changeTree();
            }
        });
    }

    protected void changeTree(){
        String date = dateListBox.getItemText(dateListBox.getSelectedIndex());
        String eventname = eventnameListBox.getItemText(eventnameListBox.getSelectedIndex());
        String djname = djnameListBox.getItemText(djnameListBox.getSelectedIndex());

        setTree(getPlaylistDateEventNameDJName(date, eventname, djname));

    }

    private void getListBox(){
        setArrayList(rootPlaylistList);

        dateListBox.clear();
        dateListBox.addItem(ANY);
        for(String date:dateList){
            dateListBox.addItem(date);
        }

        eventnameListBox.clear();
        eventnameListBox.addItem(ANY);
        for(String eventname:eventnameList){
            eventnameListBox.addItem(eventname);
        }

        djnameListBox.clear();
        djnameListBox.addItem(ANY);
        for(String djname:djnameList){
            djnameListBox.addItem(djname);
        }
    }

    private void setArrayList(ArrayList<Playlist> playlistList){
        dateList = new ArrayList<String>();
        eventnameList = new ArrayList<String>();
        djnameList = new ArrayList<String>();

        for(Playlist playlist:playlistList){
            String date = playlist.getDatetime().substring(0, 7);
            if(!dateList.contains(date)){
                dateList.add(date);
            }

            String eventname = playlist.getEventName();
            if(!eventnameList.contains(eventname)){
                eventnameList.add(eventname);
            }

            String djname = playlist.getDJName();
            if(!djnameList.contains(djname)){
                djnameList.add(djname);
            }
        }
    }

    protected void setDelete(){
        new DeleteDialog(deleteButton).show();
    }

    private class DeleteDialog extends DialogBox{

        public DeleteDialog(Button deleteButton){
            setText("Delete Playlist");
            setAnimationEnabled(true);
            setGlassEnabled(true);

            HTMLPanel content = new HTMLPanel("");
            Label deleteLabel = new Label("本当にPlaylistを削除しますか？");

            Button okButton = new Button("OK");
            okButton.addClickHandler(new ClickHandler(){
                public void onClick(ClickEvent event){
                    DeleteDialog.this.hide();
                    deletePlaylistDialog();
                }
            });

            Button cancelButton = new Button("Cancel");
            cancelButton.addClickHandler(new ClickHandler(){
                public void onClick(ClickEvent event){
                    DeleteDialog.this.hide();
                }
            });

            content.add(deleteLabel);
            content.add(okButton);
            content.add(cancelButton);

            add(content);

            setPopupPosition(deleteButton.getAbsoluteLeft(), deleteButton.getAbsoluteTop());
        }

        protected void deletePlaylistDialog(){
            deletePlaylist();

        }
    }

    public void deletePlaylist(){
        Playlist deletePlaylist = getPlaylist(keyHidden.getValue());

        if(deletePlaylist != null){
            playlistService.deletePlaylist(deletePlaylist.getKey(), new AsyncCallback<Void>(){

                public void onSuccess(Void result){
                    setInfoMessage("Playlistの削除に成功しました。");
                    clearErrorMessage();
                    playlistPanel.setVisible(false);
                    setTop();
                }

                public void onFailure(Throwable caught){
                    clearInfoMessage();
                    setErrorMessage("Playlistの削除に失敗しました。");
                }
            });
        }else{
            clearInfoMessage();
            setErrorMessage("削除に失敗しました。");
        }
    }

    protected void setTop(){
        FlowPanel mainPanel = (FlowPanel)getParent();
        mainPanel.add(new PlaylistBrowse());
        this.removeFromParent();
    }

    protected void setEdit(){
        Playlist editPlaylist = getPlaylist(keyHidden.getValue());
        if(editPlaylist != null){
            FlowPanel mainPanel = (FlowPanel)getParent();
            mainPanel.add(new CreatePlaylist(editPlaylist, passwordTextBox.getText()));
            this.removeFromParent();
        }else{
            clearInfoMessage();
            setErrorMessage("Playlistの取得に失敗しました。");
        }
    }

    private Playlist getPlaylist(String keyHiddenvalue){
        for(Playlist playlist:rootPlaylistList){
            if(playlist.getKey().toString().equals(keyHiddenvalue)){
                return playlist;
            }
        }
        return null;
    }
}
